package com.dongrj.framework.core.utils;

import com.google.common.base.CaseFormat;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.hash.Hashing;
import lombok.extern.slf4j.Slf4j;

import java.text.NumberFormat;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @author dongrongjun
 * @date 2020/08/04
 */
@Slf4j
public final class StringUtils {

    public static final String EMPTY = "";

    public static boolean isEmpty(CharSequence str) {
        return str == null || str.length() == 0;
    }

    /**
     * 判断字符串是否为空
     *
     * @param str 字符串
     */
    public static boolean isEmpty(String str, boolean isTrim) {
        if (isTrim) {
            return Objects.isNull(str) || str.trim().length() == 0;
        }
        return Objects.isNull(str) || str.length() == 0;
    }

    /**
     * 判断字符串是否为空
     *
     * @param str 字符串
     */
    public static String isEmpty(String str, Supplier<String> supplier) {
        if (isEmpty(str)) {
            return supplier.get();
        }
        return str;
    }

    /**
     * 判断字符串是否为空
     *
     * @param str 字符串
     */
    public static boolean isNull(String str) {
        return Objects.isNull(str);
    }


    /**
     * 判断字符串是否不为空
     *
     * @param str 字符串
     */
    public static boolean isNotEmpty(String str) {
        return isNotEmpty(str, true);
    }


    /**
     * 判断字符串是否不为空
     *
     * @param str 字符串
     */
    public static boolean isNotEmpty(String str, boolean isTrim) {
        return !isEmpty(str, isTrim);
    }


    /**
     * 判断字符串是否以startStr开头
     *
     * @param source   源字符串
     * @param startStr 字符串
     */
    public static boolean startsWith(String source, String startStr) {
        if (isEmpty(source)) {
            return false;
        }
        if (isEmpty(startStr)) {
            return false;
        }
        return source.startsWith(startStr);
    }


    /**
     * 判断字符串是否以startStr结尾
     *
     * @param source 源字符串
     * @param endStr 字符串
     */
    public static boolean endsWith(String source, String endStr) {
        if (isEmpty(source)) {
            return false;
        }
        if (isEmpty(endStr)) {
            return false;
        }
        return source.endsWith(endStr);
    }


    /**
     * 字符串拼接
     *
     * @param collection 字符串集合
     */
    public static String join(Collection<String> collection) {
        return join(",", true, collection);
    }

    /**
     * 字符串转Set集合
     */
    public static Set<String> toSet(String str) {
        return toSet(str, ",");
    }

    /**
     * 字符串转Set集合
     *
     * @param separator 分隔符
     */
    public static Set<String> toSet(String str, String separator) {
        if (isEmpty(str)) {
            return Collections.emptySet();
        }
        return Sets.newHashSet(str.split(separator));
    }


    /**
     * 字符串转List集合
     */
    public static List<String> toList(String str) {
        return toList(str, ",");
    }

    /**
     * 字符串转List
     *
     * @param separator 分隔符
     */
    public static List<String> toList(String str, String separator) {
        if (isEmpty(str)) {
            return Collections.emptyList();
        }
        return Lists.newArrayList(str.split(separator));
    }


    /**
     * 字符串拼接
     *
     * @param strings 字符串集合
     */
    public static String join(String... strings) {
        return join(",", true, strings);
    }


    /**
     * 字符串拼接
     *
     * @param skipNull   是否跳过null元素
     * @param collection 字符串集合
     */
    public static String join(CharSequence delimiter, boolean skipNull, Collection<String> collection) {
        if (skipNull) {
            if (CollectionUtils.isEmpty(collection)) {
                return EMPTY;
            }
            List<String> collect = collection.stream().filter(Objects::nonNull).collect(Collectors.toList());
            return String.join(delimiter, collect);
        } else {
            if (CollectionUtils.isEmpty(collection)) {
                return EMPTY;
            }
            return String.join(delimiter, collection);
        }
    }

    /**
     * 字符串拼接
     *
     * @param skipNull 是否跳过null元素
     * @param strings  字符串集合
     */
    public static String join(CharSequence delimiter, boolean skipNull, String... strings) {
        if (skipNull) {
            if (CollectionUtils.isEmpty(strings)) {
                return EMPTY;
            }
            List<String> collect = Arrays.stream(strings).filter(Objects::nonNull).collect(Collectors.toList());
            return String.join(delimiter, collect);
        } else {
            if (CollectionUtils.isEmpty(strings)) {
                return EMPTY;
            }
            return String.join(delimiter, strings);
        }
    }


    /**
     * 判断字符串对象是否都是空
     *
     * @param strings 字符串集合
     */
    public static boolean isAllEmpty(String... strings) {
        if (strings == null || strings.length == 0) {
            return true;
        }
        for (String object : strings) {
            if (isNotEmpty(object)) {
                return false;
            }
        }
        return true;
    }


    /**
     * 判断字符串对象是否都是空
     *
     * @param strings 字符串集合
     */
    public static boolean isAllNotEmpty(String... strings) {
        if (strings == null || strings.length == 0) {
            return false;
        }
        for (String object : strings) {
            if (isEmpty(object)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 任何之一为空
     *
     * @param strings 字符串集合
     */
    public static boolean isAnyEmpty(String... strings) {
        if (strings == null || strings.length == 0) {
            return true;
        }
        for (String string : strings) {
            if (isEmpty(string)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断字符串对象是否任意一个不空
     *
     * @param strings 字符串集合
     */
    public static boolean isAnyNotEmpty(String... strings) {
        for (String object : strings) {
            if (isNotEmpty(object)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 字符串填充
     *
     * @param string    原始字符串
     * @param minLength 填充到长度
     * @param padChar   填充符
     */
    public static String padEnd(String string, int minLength, char padChar) {
        return Strings.padEnd(string, minLength, padChar);
    }

    /**
     * 字符串长度
     *
     * @param str  字符串
     * @param trim 是否trim
     */
    public static int length(String str, boolean trim) {
        if (isNotEmpty(str)) {
            if (trim) {
                return str.trim().length();
            }
            return str.length();
        }
        return 0;
    }

    /**
     * 字符串长度
     *
     * @param str 字符串
     */
    public static int length(String str) {
        return length(str, false);
    }


    /**
     * 字符串Empty 转 Null
     *
     * @param str 字符串
     */
    public static String emptyToNull(String str) {
        return Strings.emptyToNull(str);
    }

    /**
     * 字符串Empty 转 Null
     *
     * @param obj 对象
     */
    public static Object emptyToNull(Object obj) {
        if (obj instanceof String) {
            String string = (String) obj;
            if (string.isEmpty()) {
                return null;
            }
        }
        return obj;
    }

    /**
     * 字符串Null 转 Empty
     *
     * @param str 字符串
     */
    public static String nullToEmpty(String str) {
        return Strings.nullToEmpty(str);
    }

    /**
     * 判断传入的字符串长度是否相等
     *
     * @param strings 字符串集合
     */
    public static boolean equalLength(String... strings) {
        if (Objects.nonNull(strings)) {
            List<Integer> collect = Arrays.stream(strings).filter(Objects::nonNull).mapToInt(String::length).boxed().sorted(Comparator.comparingInt(a -> a)).collect(Collectors.toList());
            return Objects.equals(collect.get(0), collect.get(collect.size() - 1));
        }
        return true;
    }

    /**
     * 字符串都是空
     *
     * @param strings 字符串集合
     * @return
     */
    public static boolean areNotEmpty(String... strings) {
        boolean result = true;
        if (strings == null || strings.length == 0) {
            result = false;
        } else {
            for (String value : strings) {
                result &= !isEmpty(value);
            }
        }
        return result;
    }

    /**
     * 字符串转驼峰
     * user_name -> userName
     *
     * @param str 字符串
     */
    public static String toLowerCamel(String str) {
        return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, str);
    }

    /**
     * 字符串转驼峰
     * user_name -> UserName
     *
     * @param str 字符串
     */
    public static String toUpperCamel(String str) {
        return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, str);
    }

    /**
     * 驼峰转换
     * username -> username   UserName -> user_name
     *
     * @param str 字符串
     */
    public static String toLowerUnderscore(String str) {
        return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, str);
    }

    /**
     * 将集合字符串逗号拼接
     *
     * @param collection 集合字符串
     */
    public static String toString(Collection<String> collection) {
        if (CollectionUtils.isEmpty(collection)) {
            return "";
        }
        return Joiner.on(",").join(collection);
    }


    /**
     * 将集合字符串拼接起来
     *
     * @param collection 集合字符串
     * @param separator  分隔符
     */
    public static String toString(Collection<String> collection, String separator) {
        if (StringUtils.isEmpty(separator)) {
            return toString(collection);
        }
        return Joiner.on(separator).join(collection);
    }

    /**
     * 无作用消除波浪线
     *
     * @param string 字符串
     */
    public static String toString(String string) {
        return string;
    }

    /**
     * 将数组字符串逗号拼接
     *
     * @param arrays 数组字符串
     */
    public static String toString(String[] arrays) {
        if (CollectionUtils.isEmpty(arrays)) {
            return "";
        }
        return Joiner.on(",").join(arrays);
    }


    /**
     * 将数组字符串拼接起来
     *
     * @param arrays    集合字符串
     * @param separator 分隔符
     */
    public static String toString(String[] arrays, String separator) {
        if (StringUtils.isEmpty(separator)) {
            return toString(Arrays.asList(arrays));
        }
        return Joiner.on(separator).join(arrays);
    }

    /**
     * 判断子字符串是否相等
     *
     * @param str1 字符串1
     * @param str2 字符串2
     */
    public static boolean equals(String str1, String str2) {
        if (Objects.isNull(str1)) {
            return Objects.isNull(str2);
        }
        return str1.equals(str2);
    }

    /**
     * 数字转百分比
     *
     * @param number 数字
     */
    public static String toPercent(Number number) {
        return toPercent(number, 2);
    }

    /**
     * 数字转百分比
     *
     * @param number       数字
     * @param digitsLength 小数点个数
     */

    public static String toPercent(Number number, int digitsLength) {
        NumberFormat defaultFormat = NumberFormat.getPercentInstance();
        defaultFormat.setMinimumFractionDigits(digitsLength);
        return defaultFormat.format(number);
    }

    /**
     * 字符串长度切分
     *
     * @param str  yyyyMMdd
     * @param lens 4,2,2
     */
    public static List<String> lengthSplit(String str, int... lens) {
        List<String> result = Lists.newArrayList();
        int index = 0;
        for (int len : lens) {
            if (index > str.length()) {
                return result;
            } else {
                int end = Math.min(len + index, str.length());
                result.add(str.substring(index, end).trim());
                index += len;
            }
        }
        return result;
    }

    public static String lengthSplitJoin(String str, String separation, int... lens) {
        List<String> strings = lengthSplit(str, lens);
        return Joiner.on(separation).join(strings);
    }

    /**
     * 隐藏手机号
     *
     * @param mobileNum 手机号
     */
    public static String hideMobileNum(String mobileNum) {
        List<String> strings = lengthSplit(mobileNum, 3, 4, 4);
        if (CollectionUtils.size(strings) < 3) {
            return mobileNum;
        }
        return String.format("%s****%s", strings.get(0), strings.get(2));
    }

    /**
     * 隐藏IDCard
     *
     * @param idCardNum 身份证号
     */
    public static String hideIdCardNum(String idCardNum) {
        List<String> strings = lengthSplit(idCardNum, 6, 8, 4);
        if (CollectionUtils.size(strings) < 3) {
            return idCardNum;
        }
        return String.format("%s********%s", strings.get(0), strings.get(2));
    }

    /**
     * 获取时分秒
     *
     * @param date 日期
     */
    public static String getTraceId(String prefix, Date date) {
        if (isNotEmpty(prefix)) {
            return prefix + DateUtils.toString(date, "MMddHHmmss");
        }
        return DateUtils.toString(date, "MMddHHmmss");
    }

    /**
     * 获取时分秒
     */
    public static String getTraceId() {
        return getTraceId("", new Date());
    }

    /**
     * 获取时分秒
     */
    public static String getTraceId(String prefix) {
        return getTraceId(prefix, new Date());
    }


    /**
     * 随机密码
     *
     * @param len 密码长度
     */
    public static String random(int len) {
        String str = "123456789QqWwEeRrTtYyUuIiPpAaSsDdFfGgHhJjKkLlZzXxCcVvBbNnMm";
        return random(len, str);
    }

    /**
     * 随机密码
     *
     * @param len 密码长度
     * @param str 密码内容范围
     */
    public static String random(int len, String str) {
        if (isEmpty(str)) {
            return str;
        }
        Random random = new Random();
        char[] result = new char[len];
        for (int i = 0; i < len; i++) {
            int randomNum = random.nextInt(str.length() - 1);
            result[i] = str.charAt(randomNum);
        }
        return new String(result);
    }


    /**
     * 字符串是否包含
     *
     * @param str       字符串
     * @param searchStr 被包含的字符串
     */
    public static boolean contains(String str, String searchStr) {
        return str != null && searchStr != null && str.contains(searchStr);
    }

    /**
     * 判断字符串是否都是一样的字符
     *
     * @param str 字符
     * @param c   字符
     */
    public static boolean isAllChar(String str, char c) {
        if (isEmpty(str)) {
            return false;
        }
        String s = Strings.padEnd("", str.length(), c);
        return Objects.equals(s, str);
    }


    /**
     * 判断字符串是否为纯数字
     *
     * @param str 字符串
     */
    public static boolean isNumeric(String str) {
        if (isEmpty(str)) {
            return false;
        }
        for (int i = str.length(); --i >= 0; ) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }


    /**
     * 判断字符串是否为纯数字
     *
     * @param str 字符串
     */
    public static boolean isPositiveInt(String str) {
        if (isEmpty(str)) {
            return false;
        }
        if (str.startsWith("0")) {
            return false;
        }
        return isNumeric(str);
    }

    /**
     * 判断字符串是否为纯数字
     *
     * @param str 字符串
     */
    public static boolean isNegtiveInt(String str) {
        if (isEmpty(str)) {
            return false;
        }
        if (!str.startsWith("-")) {
            return false;
        }
        if (str.startsWith("-0")) {
            return false;
        }
        str = str.substring(1);
        return isNumeric(str);
    }


    public static boolean isCalcNum(String str) {
        return isCalcNum(str, 20);
    }

    /**
     * 判断字符串是否为可以参与数学计算数字字符串(只判断前validLength位)
     *
     * @param str 字符串
     */
    public static boolean isCalcNum(String str, int maxLength) {
        if (isEmpty(str) || str.startsWith(".")) {
            return false;
        }
        if (str.length() > maxLength) {
            throw new RuntimeException(str + "超过指定长度:" + maxLength);
        }
        if (str.startsWith("-")) {
            if (str.length() < 2) {
                return false;
            }
            str = str.substring(1);
        }
        if (str.contains(".")) {
            String[] split = str.split("\\.");
            if (split.length > 2) {
                return false;
            }
            if (split[0].length() > 1) {
                if (split[0].startsWith("0")) {
                    return false;
                }
            }
            str = split[0] + split[1];
        } else {
            if (str.startsWith("0")) {
                return false;
            }
        }
        return isNumeric(str);
    }

    /**
     * 随机UUID字符串
     */
    public static String randomUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 是否以suffix结尾
     *
     * @param source 源字符串
     * @param suffix 后缀字符串
     */
    public static boolean endsWithIgnoreCase(String source, String suffix) {
        if (length(suffix) > length(source)) {
            return false;
        }
        String substring = source.substring(source.length() - suffix.length());
        return substring.equalsIgnoreCase(suffix);
    }

    /**
     * 是否相等
     *
     * @param str1 字符串1
     * @param str2 字符串2
     */
    public static boolean equalsIgnoreCase(String str1, String str2) {
        return !isNull(str1) && !isNull(str2) && str1.equalsIgnoreCase(str2);
    }

    /**
     * 返回默认值
     *
     * @param str          字符串
     * @param defaultValue 默认值
     */

    public static String defaultIfEmpty(String str, String defaultValue) {
        if (isEmpty(str)) {
            return defaultValue;
        }
        return str;
    }


    /**
     * 是否和任何一个字符串相等
     *
     * @param str  当前字符串
     * @param strs 要比较的字符串
     */
    public static boolean equalsAny(String str, String... strs) {
        for (String s : strs) {
            if (StringUtils.equals(s, str)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 返回默认值
     *
     * @param str          字符串
     * @param defaultValue 默认值
     */

    public static String defaultIfEmpty(String str, Supplier<String> defaultValue) {
        if (isEmpty(str)) {
            return defaultValue.get();
        }
        return str;
    }


    /**
     * 返回默认值
     *
     * @param str          字符串
     * @param defaultValue 默认值
     */

    public static String defaultIfNull(String str, String defaultValue) {
        if (isNull(str)) {
            return defaultValue;
        }
        return str;
    }


    public static String getSubBetween(String str, String open, String close) {
        if (str == null || open == null || close == null) {
            return null;
        }
        int start = str.indexOf(open);
        if (start != -1) {
            int end = str.indexOf(close, start + open.length());
            if (end != -1) {
                if (end < start) {
                    return null;
                }
                return str.substring(start + open.length(), end);
            }
        }
        return null;
    }

    /**
     * @param str       字符串
     * @param minLength 最小长度
     * @param maxLength 最大长度
     */
    private boolean lengthBetween(String str, int minLength, int maxLength) {
        if (minLength < 0 || maxLength < 0) {
            throw new RuntimeException("参数有误!");
        }
        int strLength = 0;
        if (StringUtils.isNotEmpty(str)) {
            strLength = str.length();
        }
        return strLength >= minLength && strLength <= maxLength;
    }


    /**
     * 随机字符串
     *
     * @param object 字符串长度
     */
    public static String toString(Object object) {
        if (Objects.isNull(object)) {
            return null;
        }
        return object.toString();
    }

    /**
     * MD5加密
     *
     * @param str 字符串
     */
    public static String md5(String str) {
        if (isEmpty(str)) {
            return "";
        }
        return Hashing.md5().newHasher()
                .putString(str, Charsets.UTF_8)
                .hash()
                .toString();
    }

    /**
     * 返回默认值
     *
     * @param object       对象
     * @param defaultValue 默认值
     */

    public static String toString(Object object, String defaultValue) {
        if (Objects.isNull(object)) {
            return defaultValue;
        }
        return object.toString();
    }

    /**
     * 随机字符串
     *
     * @param object 字符串转Long
     */
    public static Long toLong(Object object) {
        if (Objects.isNull(object)) {
            return null;
        }
        String s = object.toString();
        return Long.parseLong(s);
    }

    /**
     * 首字母大写
     *
     * @param string 字符串
     * @return 字符串
     */
    public static String upperInitials(String string) {
        string = string.substring(0, 1).toUpperCase() + string.substring(1);
        return string;
    }

    /**
     * 首字母小写
     *
     * @param string 字符串
     * @return 字符串
     */
    public static String lowerInitials(String string) {
        string = string.substring(0, 1).toLowerCase() + string.substring(1);
        return string;
    }


    /**
     * 字符串结尾拼接
     *
     * @param string 字符串
     * @param suffix 结尾
     */
    public static String appendIfNotEndWith(String string, String suffix) {
        if (StringUtils.isNotEmpty(string)) {
            if (string.endsWith(suffix)) {
                return string;
            } else {
                return string + suffix;
            }
        }
        throw new RuntimeException();
    }

    /**
     * @param source    字符串
     * @param separator 分隔符
     */
    public static String[] split(String source, String separator) {
        if (isEmpty(source)) {
            return new String[]{};
        }
        return source.split(separator);
    }

    /**
     * 是不是字符串True
     *
     * @param string 字符串
     */
    public static boolean isTrue(String string) {
        if (isEmpty(string)) {
            return false;
        }
        return Objects.equals(string.trim(), "true");
    }

    /**
     * 是不是字符串False
     *
     * @param string 字符串
     */
    public static boolean isFalse(String string) {
        return !isTrue(string);
    }

    /**
     * 删除空白符(同时也会删除换行符)
     *
     * @param str 字符串
     */
    public static String deleteWhitespace(String str) {
        if (isEmpty(str)) {
            return str;
        }
        final int sz = str.length();
        final char[] chs = new char[sz];
        int count = 0;
        for (int i = 0; i < sz; i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                chs[count++] = str.charAt(i);
            }
        }
        if (count == sz) {
            return str;
        }
        return new String(chs, 0, count);
    }

    public static void notEmpty(String str, Consumer<String> consumer) {
        if (isNotEmpty(str)) {
            consumer.accept(str);
        }
    }

}
